#include <stdio.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <iostream>
#include <sys/ioctl.h>
#include <netdb.h>
#include "controller.h"
#include "message.h"


using namespace std;

int readMessage(int fd, char* buf);

int main(int argc, char** argv)
{
	const size_t MSG_SIZE = 4096;
	int _sock, opt;
	sockaddr_in servaddr;
	char message[MSG_SIZE];
	Message msg;
	Controller _controller;
	if (argc != 3) 
	{
		cerr<<"Usage: "<<argv[0]<<" host port\n";
		return 0;
	}
	cerr<<"Host = "<<argv[1]<<", port = "<<argv[2]<<"\n";
	_sock = socket(AF_INET, SOCK_STREAM, 0);
	if (_sock < 0)
		perror("error creating socket");
	opt = 1;
	int res;
	hostent* ptr = 0;
	ptr = gethostbyname(argv[1]);
	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;
	servaddr.sin_port = htons(atoi(argv[2]));
	in_addr inaddr;
	if(ptr == 0)
	{	
		inaddr.s_addr = (unsigned long)inet_addr(argv[1]);
		//cerr<<"get host by name returned 0\n";
	}
	else
	{
		inaddr.s_addr = *((unsigned *)ptr->h_addr_list[0]);
		//cerr<<" host name is "<<ptr->h_name<<"\n";
		//cerr<<" addr is ["<<(int)ptr->h_addr_list[0][0]<<","<<
		//					(int)ptr->h_addr_list[0][1]<<","<<
		//					(int)ptr->h_addr_list[0][2]<<","<<
		//					(int)ptr->h_addr_list[0][3]<<"]"<<"\n";
		//cerr<<" expr is "<<(unsigned)*((unsigned *)ptr->h_addr_list[0])<<"\n";
		
	}
	servaddr.sin_addr = inaddr;
	unsigned long val = 1;
	
	res = connect(_sock, (sockaddr *)&servaddr, sizeof(servaddr));
	if(res) 
	{
		perror("server connect");
		close(_sock);
	}
	res = setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, (char *)&opt, sizeof(opt));
	if(res)
	{
		perror("setsockopt error");
		close(_sock);
		return 0;
	}
	//if(ioctl(_sock, FIONBIO, &val))
	//{
	//	perror("set nonblocking mode");
	//	close(_sock);
	//	return 0;
	//}
	while(res = readMessage(_sock, message) > 0)
	{
		res = msg.parse(message);
		if(res)
		{
			cerr<<"Error parsing message:"<<res<<"\n";
			close(_sock);
			return 0;
		}
		char* resp = 0;
		switch(msg.mType)
		{
			case 'I':
				resp = _controller.init(&msg);
			break;
			case 'T':
				resp = _controller.makeDecision(&msg);
			break;
			case 'B':
			case 'C':
			case 'K':
			case 'S':
				resp = _controller.notify(&msg);
			break;
			case 'E':
				resp = _controller.cleanup(&msg);
			break;
			default:
				cerr<<"Unknown message\n";
				close(_sock);
				return 0;
		}
		unsigned len = strlen(resp);
		if(len)
			send(_sock, resp, len, 0);
	}
	cerr<<"size is "<<res<<", closing connection\n";
	close(_sock);
	return 0;
}

int readMessage(int fd, char* buf) 
{
	int ret = 0, res;
	const size_t READ_SIZE = 1;
	char inputBuf[READ_SIZE + 1];

	while(res = recv(fd, inputBuf, READ_SIZE, 0) > 0)
	{
		buf[ret] = inputBuf[0];
		ret++;
		if(inputBuf[0] == ';')
		{
			buf[ret] = 0;	
			return ret;
		}
	}
	buf[ret] = 0;
	return ret;
} 
